home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
233_01
/
make.c
< prev
next >
Wrap
Text File
|
1987-06-29
|
13KB
|
527 lines
/*
* Program Name : MAKE.C
* Author : Allen Holub
* Implementor : Kenji Hino
* Compiler : Microsoft ver. 4.0, Lattice C ver. 3
* Description : MAKE is the program that maintains programs.
* MAKE takes resposibility for recompiling or linking
* any source or object codes if any of them has
* updated.
*/
#include "make.h"
void main(argc, argv)
char **argv;
int argc;
{
int dependancies(), make(), err();
if( !(Makefile = fopen(MAKEFILE, "r")) )
err("can't open %s\n", MAKEFILE);
if( !dependancies() )
err("Nothing to make");
else
make( argc > 1 ? argv[1] : First);
} /* main end */
char *gmem( numbytes )
int numbytes;
{
/* Get numbytes from malloc. Print an error messages and
abort if malloc fails, otherwise return a pointer to
the memory.
*/
char *calloc();
char *p;
int err();
if( !( p = calloc(1, numbytes) ))
err("Out of memory");
return p;
} /* gmem end */
char **stov(str, maxvect)
char *str;
int maxvect;
{
/* "Str" is a string of words seperated from each other by
white space. Stov returns an argv-like array of pointers
to chracter pointers, one to each word in the original
string. The white-space in the original string is replaced
with nulls. The array of pointers is null-terminated
array. The program is aborted of it can't get memory.
*/
char **vect, **vp;
char *gmem();
vp = vect = (char **) gmem( (maxvect + 1) * sizeof(str) );
while( *str && --maxvect >= 0 )
{
skipwhite(str);
*vp++ = str;
skipnonwhite(str);
if(*str)
*str++ = 0;
}
*vp = 0;
return(vect);
} /* stov end */
long gtime( file )
char *file;
{
/* Return the time and date for file.
The DOS time and date are concatenated to form one
large number. Note that the high bit of this number
will be set to 1 for all dates after 2043, which will
cause the date comparisons done in make() to not work.
THIS ROUTINE IS NOT PORTABLE (because it assumes a 32 bit
long).
*/
long time;
int fd;
int open(), err(), close();
#ifdef MICRO_C
struct stat buf;
int fstat();
int result;
#endif
#ifdef LATTICE_C
long getft();
#endif
if ( (fd = open (file, O_RDONLY)) == -1 )
return DEFTIME;
#ifdef MICRO_C
if ( (result = fstat (fd, &buf)) == -1 )
err("DOS returned error from date/time request");
time = buf.st_atime;
#endif
#ifdef LATTICE_C
/* LATTICE uses a different time structure from one returned by */
/* gmtime() so that it doesn't show the same file time as one you get */
/* by "dir" command. However, it still can tell the difference */
/* between new and old files. */
if ( (time = getft (fd)) == -1 )
err("DOS returned error from date/time request");
#endif
if ( close (fd) )
err("DOS returned error from file close request");
return time;
} /* gtime end */
TNODE *makenode()
{
/* Create a TNODE, filling it from the makefile
and return a pointer to it. Return NULL if there are no more
objects in the makefile.
*/
char *line, *lp;
TNODE *nodep;
char *getline(), **stov(), **getblock(), *gmem();
int err();
long gtime();
/* First, skip past any blank lines or comment lines.
Return NULL if we reach the end of file
*/
do{
if( (line = getline(MAXLINE, Makefile)) == NULL )
return( NULL );
} while ( *line == 0 || *line == COMMENT );
/* At this point we've gotten what should be the dependancy
line. Position lp to point at the colon.
*/
for( lp = line; *lp && *lp != ':'; lp++)
;
/* If we find the colon position, lp to point at the first
non-white character following the colon.
*/
if( *lp != ':' )
err("missing ':'"); /* This will abort the program */
else
for( *lp++ = 0; iswhite(*lp) ; lp++)
;
/* Allocate and initialize the TNODE */
nodep = (TNODE *) gmem( sizeof(TNODE) );
nodep->being_made = line;
nodep->time = gtime( line );
nodep->depends_on = stov( lp, MAXDEP );
nodep->do_this = getblock( Makefile );
return( nodep );
} /* makenode end */
int dependancies()
{
/* Manufacture the binary tree of objects to make. First
is a pointer to the first target file listed in the
makefile (i.e. the one to make if one isn't explicitly
given on the command line). Root is the tree's root pointer.
*/
TNODE *node, *makenode();
int err(), tree();
if( node = makenode() )
{
First = node->being_made;
if( !tree(node, &Root) )
err("Can't insert first node into tree !!!\n");
while( node = makenode() )
if( !tree(node, &Root) )
free(node);
return 1;
}
return 0;
} /* dependancies end */
char *getline( maxline, fp)
int maxline;
FILE *fp;
{
/* Get a line from the stream pointed to by fp.
"Maxline" is the maximum input line size ( including the
terminating null. A \ at the end of line is
recognized as a line continuation, ( the lines
are concatenated). Buffer space is gotten from malloc.
If a line is longer than maxline it is truncated (i.e.
all characters from the maxlineth until a \n or EOF is
encountered are discarded.
Return: NULL on a malloc failure or the end of file.
A pointer to the malloced buffer on success.
*/
static char *buf;
register char *bp;
register int c, lastc;
char *malloc(), *strcpy();
/* Two buffers are used, Here, we are getting a worst-case buffer
that will hold the longest possible line. Later on we'll copy
the string into a buffer that's the correct size.
*/
if( !(bp = buf = malloc(maxline)) )
return NULL;
while(1)
{
/* Get the line from fp. Terminate after maxline
characters and ignore \n following a \.
*/
Inputline++; /* Update input line number */
for( lastc=0; (c = fgetc(fp)) != EOF && c!='\n'; lastc = c)
if( --maxline > 0 )
*bp++ = c;
if( !(c == '\n' && lastc == '\\') )
break;
else if(maxline > 0) /* erase the \ */
--bp;
}
*bp = 0;
if( (c == EOF && bp == buf) || !(bp = malloc((bp-buf) + 1)) )
{
/* If EOF was the first character on the line or
malloc fails when we try to get a buffer, quit.
*/
free(buf);
return( NULL );
}
strcpy (bp, buf); /* Copy the worst-case buffer to the one */
/* that is the correct size and ... */
free ( buf ); /* free the original, worst-case buffer, */
return ( bp ); /* returning a pointer to the copy */
} /* getline end */
char **getblock( fp )
FILE *fp;
{
/* Get a block from standard input. A block is a sequences of
lines terminates by a blank line. The block is returned as
an array of pointers to strings. At most MAXBLOCK lines can
be in a block. Leading white space is stripped.
*/
char *p, *lines[MAXBLOCK], **blockv = lines, *gmem();
int blockc = 0;
char *memcpy(), *getline(), *gmem();
int err();
do {
if( !( p = getline(MAXLINE, Makefile) ))
break;
skipwhite(p);
if( ++blockc <= MAXBLOCK )
*blockv++ = p;
else
err("action too long (max = %d lines)", MAXBLOCK);
} while(*p);
/* Copy the blockv array into a safe place. Since the array
returned by getblock is NULL terminated, we need to
increment block first.
*/
blockv = (char **) gmem( (blockc + 1) * sizeof(blockv[0]) );
memcpy( blockv,lines, blockc * sizeof(blockv[0]) );
blockv[blockc] = NULL;
return blockv;
} /* getblock end */
int err( msg, param)
char *msg;
int param;
{
/* Print the error message and exit the program. */
fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
fprintf(stderr, msg, param);
exit(1);
} /* err end */
int serr( msg, param )
char *msg, *param;
{
/* same as err() except the parameter is a string pointer
instead pf an int.
*/
fprintf(stderr, "Mk (%s line %d): ", MAKEFILE, Inputline);
fprintf(stderr, msg, param);
exit(1);
} /* serr end */
int make(what)
char *what;
{
/* Actually do the make. the dependancy tree is desc